﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CodeCrawler.UI.Data;
using CodeCrawler.UI.Engine.KeyPointersScan;
using CodeCrawler.UI.Functionalities.VisualStudio;
using OWASP.CodeReview.CodeCrawler.Enums;
using Puzzle.SourceCode;

namespace CodeCrawler.UI.Forms
{
    public partial class VisualStudioSolution : Form
    {
        /// <summary>
        /// This will act as a container for all the threats found into the current file
        /// </summary>
        public DataTable CurrentThreatListDataTable = new DataTable("ThreatList");
        /// <summary>
        /// Code Crawler Database
        /// </summary>
        public DataSet xmlCodeCrawlerDatabase { get; set; }
        /// <summary>
        /// Code Crawler Threat List
        /// </summary>
        public DataTable threatList { get; set; }

        public VisualStudioSolution()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Current File Name
        /// </summary>
        private string FileName { get; set; }
        /// <summary>
        /// Current Folder
        /// </summary>
        private string FolderName { get; set; }


        /// <summary>
        /// Set uiCodeViewer Properties
        /// </summary>
        private void SetCodeViewerValues()
        {
            uiCodeView.Visible = true;
            uiCodeView.Document.SyntaxFile = Application.StartupPath + "\\C#.syn";
            uiCodeView.Document.Text = string.Empty;
        }


        /// <summary>
        /// Open a new Visual Studio Solution
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OpenVisualStudioSolutionItemClick(object sender, EventArgs e)
        {

        }


        /// <summary>
        /// Load Code Crawler Database
        /// </summary>
        /// <param name="DatabaseHelper"></param>
        private void LoadCodeReviewDataBase(CodeCrawlerXMLDatabase DatabaseHelper)
        {
            DatabaseHelper.CreateThreatTable(CurrentThreatListDataTable);
            xmlCodeCrawlerDatabase = DatabaseHelper.InizializeCodeCrawlerDatabase();
        }


        /// <summary>
        /// Create Code Crawler Threat Table
        /// </summary>
        /// <param name="dataTableToCreate"></param>
        public void CreateThreatTable(DataTable dataTableToCreate)
        {
            if (dataTableToCreate != null)
            {
                var column1 = new DataColumn("Threat", typeof(string));
                var column2 = new DataColumn("Description", typeof(string));
                var column3 = new DataColumn("Level", typeof(ThreatLevel));
                var column4 = new DataColumn("Line", typeof(int));
                var column5 = new DataColumn("Owasp", typeof(string));

                dataTableToCreate.Columns.Add(column1);
                dataTableToCreate.Columns.Add(column2);
                dataTableToCreate.Columns.Add(column3);
                dataTableToCreate.Columns.Add(column4);
                dataTableToCreate.Columns.Add(column5);
            }
        }

        /// <summary>
        /// Do Line Coulouring
        /// </summary>
        private void AlterSourceCodeViewerColor()
        {
            int lineNumber;

            try
            {
                for (int index = 0;
                     index < CurrentThreatListDataTable.Rows.Count;
                     index++)
                {
                    lineNumber = Convert.ToInt32(CurrentThreatListDataTable.Rows[index][3]);
                    Row r;
                    r = uiCodeView.Document[lineNumber - 1];

                    switch ((ThreatLevel)CurrentThreatListDataTable.Rows[index][2])
                    {
                        case ThreatLevel.Green:
                            r.BackColor = Color.DarkSeaGreen;
                            r.Tag = index;
                            break;
                        case ThreatLevel.Yellow:
                            r.BackColor = Color.PaleGoldenrod;
                            r.Tag = index;
                            break;
                        case ThreatLevel.Red:
                            r.BackColor = Color.IndianRed;
                            r.Tag = index;
                            break;
                        default:
                            r.BackColor = Color.Red;
                            r.Tag = index;
                            break;
                    }
                }
            }
            catch (InvalidCastException)
            {
                //TODO: This error should happen only when some one has changed the datatable
                //should log a message into a logger
            }
        }


        /// <summary>
        /// Event ++ Source Code file changes ++
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sourceCodeFileChanged(object sender, EventArgs e)
        {

            // Unload List
            CurrentThreatListDataTable.Rows.Clear();
            CurrentThreatListDataTable.Columns.Clear();

            // Clean uiCodeView.Text property
            uiCodeView.Text = string.Empty;
            int totalNumberOfLines = 0;

            string currentFileName = string.Concat(FolderName, uiListBoxFiles.SelectedItem);

            // Load Source Code file into CodeView
            if (!string.IsNullOrEmpty(currentFileName))
            {
                var builder = new StringBuilder();
                using (TextReader reader = File.OpenText(currentFileName))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        builder.AppendLine(line);
                        totalNumberOfLines++;
                    }
                }

                // Add file details to UI(
                uiCodeView.Document.Text = builder.ToString();
                uiCurrentFile.Text = uiListBoxFiles.SelectedItem.ToString();
                uiNumberOfLines.Text = totalNumberOfLines.ToString();

                // Do Single File Scan
                // Bug Fixed: Thanks to Ledieu
                ScanSingleFile(currentFileName);

                /// AlterSourceCodeViewer       -> Different Thread
                var sourceCodeViewerColorsthreadStart
                    = new ThreadStart(AlterSourceCodeViewerColor);

                // Separate CodeColouring from the UI Thread
                var codeColouring = new Thread(sourceCodeViewerColorsthreadStart);
                codeColouring.Start();
            }
        }

        /// <summary>
        /// Do Single File Scan
        /// </summary>
        private void ScanSingleFile(string currentFile)
        {
            var databaseHelper = new CodeCrawlerXMLDatabase();
            LoadCodeReviewDataBase(databaseHelper);

            Core.ScanEngine(ref CurrentThreatListDataTable, xmlCodeCrawlerDatabase, currentFile);
            uiNumberofThreats.Text = CurrentThreatListDataTable.Rows.Count.ToString();
        }

        private void HighlightProblem(object sender, Puzzle.Windows.Forms.SyntaxBox.RowMouseEventArgs e)
        {
            int tableIndex;

            if (e.Row.Tag != null)
            {
                tableIndex = Convert.ToInt32(e.Row.Tag);
                uiDescription.Text = CurrentThreatListDataTable.Rows[tableIndex][1].ToString();
            }
        }

        private void label3_Click(object sender, EventArgs e)
        {

        }

        private void VisualStudioSolution_Load(object sender, EventArgs e)
        {

            uiVSSolutionfileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            uiVSSolutionfileDialog.Filter = "C# Project file (*.csproj)|*.csproj|VB.NET Project file (*.vbproj)|*.vbproj";

            // Prepare uiCodeView control
            SetCodeViewerValues();



            if (uiVSSolutionfileDialog.ShowDialog() == DialogResult.OK)
            {
                FileName = uiVSSolutionfileDialog.SafeFileName;

                uiProjectName.Text = FileName.Replace(".csproj", string.Empty);

                int safeNameLenght = uiVSSolutionfileDialog.SafeFileName.Length;
                int pathLenght = uiVSSolutionfileDialog.FileName.Length;

                FolderName = uiVSSolutionfileDialog.FileName.Substring(0, (pathLenght - safeNameLenght));
            }

            if (!string.IsNullOrEmpty(FileName))
            {
                var codeCrawlerForVisualStudio = new CSPROJParser(FolderName, FileName);


                List<string> allFiles = codeCrawlerForVisualStudio.OpenProjectRetrieveFiles();
                uiNumberOfFiles.Text = allFiles.Count.ToString();

                if (codeCrawlerForVisualStudio.FileCOunt > 0)
                {
                    allFiles.ForEach(singleFile => uiListBoxFiles.Items.Add(singleFile));
                }
            }
        }



    }
}